﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Collections;

namespace Net.Commons.Lang {
    public class ToStringBuilder {
        public static string ToString(object obj) {
            return new InternalToStringBuilder().ToString(obj);
        }
        public static string ToStringFormat(string format, params object[] objs) {
            List<string> list = new List<string>();
            foreach (object obj in objs) {
                list.Add(new InternalToStringBuilder().ToString(obj));
            }
            return string.Format(format, list.ToArray());
        }
    }

    class InternalToStringBuilder {
        StringBuilder builder = new StringBuilder();
        public string ToString(object obj) {
            if (obj == null) {
                builder.Append(nullText);
            }
            this.AppendInternal(obj);
            return builder.ToString();
        }

        public void AppendInternal(object obj) {
            if (null == obj) {
                builder.Append(this.nullText);
                return;
            }
            Type t = obj.GetType();
            if (t.IsArray) {
                AppendArray((Array)obj);
            } else if (t == typeof(string)) {
                this.AppendString((string)obj);
            } else if (t.Namespace == NAMESPACE_SYSTEM) {
                this.Append(obj);
            } else if (new List<Type>(t.GetInterfaces()).Contains(typeof(IDictionary))) {
                AppendDictionary((IDictionary)obj);
            } else if (new List<Type>(t.GetInterfaces()).Contains(typeof(ICollection))) {
                AppendCollection((ICollection)obj);
            } else {
                this.AppendObject(obj, t);
            }
        }

        public void Append(object obj) {
            string s = obj.ToString();
            if (string.IsNullOrEmpty(s)) {
                builder.Append(this.nullText);
                return;
            }
            builder.Append(s);
        }

        public void AppendString(string s) {
            builder.Append(this.stringSeparator);
            builder.Append(s);
            builder.Append(this.stringSeparator);
        }

        public void AppendObject(object obj, Type t) {
            builder.Append(t.Name);
            builder.Append(this.objectStart);
            int i = 0;
            foreach (PropertyInfo info in t.GetProperties()) {
                if (i != 0) {
                    builder.Append(this.comma);
                }
                builder.Append(info.Name);
                builder.Append(this.equal);
                this.AppendInternal(info.GetValue(obj, null));
                i++;
            }
            builder.Append(this.objectEnd);
        }

        public void AppendDictionary(IDictionary dict) {
            builder.Append(this.contentStart);
            int i = 0;
            foreach (object key in dict.Keys) {
                if (i != 0) {
                    builder.Append(this.comma);
                }
                this.AppendInternal(key);
                builder.Append(this.equal);
                this.AppendInternal(dict[key]);
                i++;
            }
            builder.Append(this.contentEnd);
        }

        public void AppendArray(Array array) {
            builder.Append(this.arrayStart);
            int i = 0;
            foreach (object obj in array) {
                if (i != 0) {
                    builder.Append(this.comma);
                }
                this.AppendInternal(obj);
                i++;
            }
            builder.Append(this.arrayEnd);
        }

        public void AppendCollection(ICollection collection) {
            builder.Append(this.contentStart);
            int i = 0;
            foreach (object obj in collection) {
                if (i != 0) {
                    builder.Append(this.comma);
                }
                this.AppendInternal(obj);
                i++;
            }
            builder.Append(this.contentEnd);
        }

        private readonly string NAMESPACE_SYSTEM = "System";
        private string stringSeparator = "\"";
        private string equal = "=";
        private string objectStart = "<";
        private string objectEnd = ">";
        private string arrayStart = "[";
        private string arrayEnd = "]";
        private string comma = ", ";
        private string contentStart = "{";
        private string contentEnd = "}";
        private string nullText = "<null>";
    }
}
